zynqmp: pm: Implement IOCTL APIs for device control
authorRajan Vaja <[email protected]>
Wed, 17 Jan 2018 10:39:24 +0000 (02:39 -0800)
committerJolly Shah <[email protected]>
Thu, 15 Mar 2018 17:23:36 +0000 (10:23 -0700)
Implement ioctl APIs which uses MMIO operations
to configure devices. Below IOCTLs are supported
in this patch:
  * Set tap delay bypass
  * Set SGMII mode
  * SD reset
  * Set SD/MMC tap delay

Signed-off-by: Rajan Vaja <[email protected]>
Signed-off-by: Jolly Shah <[email protected]>
plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
plat/xilinx/zynqmp/zynqmp_def.h

index 6f94f420f86c7d8f77377998b5126784518623b8..c881d1248eb4529cd3741325f1b6b0b4890e30d0 100644 (file)
@@ -140,6 +140,195 @@ static enum pm_ret_status pm_ioctl_config_tcm_comb(unsigned int value)
        return PM_RET_SUCCESS;
 }
 
+/**
+ * pm_ioctl_set_tapdelay_bypass() -  Enable/Disable tap delay bypass
+ * @type       Type of tap delay to enable/disable (e.g. QSPI)
+ * @value      Enable/Disable
+ *
+ * This function enable/disable tap delay bypass.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_tapdelay_bypass(unsigned int type,
+                                                      unsigned int value)
+{
+       if ((value != PM_TAPDELAY_BYPASS_ENABLE &&
+            value != PM_TAPDELAY_BYPASS_DISABLE) || type >= PM_TAPDELAY_MAX)
+               return PM_RET_ERROR_ARGS;
+
+       return pm_mmio_write(IOU_TAPDLY_BYPASS, TAP_DELAY_MASK, value << type);
+}
+
+/**
+ * pm_ioctl_set_sgmii_mode() -  Set SGMII mode for the GEM device
+ * @nid                Node ID of the device
+ * @value      Enable/Disable
+ *
+ * This function enable/disable SGMII mode for the GEM device.
+ * While enabling SGMII mode, it also ties the GEM PCS Signal
+ * Detect to 1 and selects EMIO for RX clock generation.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_sgmii_mode(enum pm_node_id nid,
+                                                 unsigned int value)
+{
+       unsigned int val, mask, shift;
+       int ret;
+
+       if (value != PM_SGMII_DISABLE && value != PM_SGMII_ENABLE)
+               return PM_RET_ERROR_ARGS;
+
+       switch (nid) {
+       case NODE_ETH_0:
+               shift = 0;
+               break;
+       case NODE_ETH_1:
+               shift = 1;
+               break;
+       case NODE_ETH_2:
+               shift = 2;
+               break;
+       case NODE_ETH_3:
+               shift = 3;
+               break;
+       default:
+               return PM_RET_ERROR_ARGS;
+       }
+
+       if (value == PM_SGMII_DISABLE) {
+               mask = GEM_SGMII_MASK << GEM_CLK_CTRL_OFFSET * shift;
+               ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0);
+       } else {
+               /* Tie the GEM PCS Signal Detect to 1 */
+               mask = SGMII_SD_MASK << SGMII_SD_OFFSET * shift;
+               val = SGMII_PCS_SD_1 << SGMII_SD_OFFSET * shift;
+               ret = pm_mmio_write(IOU_GEM_CTRL, mask, val);
+               if (ret)
+                       return ret;
+
+               /* Set the GEM to SGMII mode */
+               mask = GEM_CLK_CTRL_MASK << GEM_CLK_CTRL_OFFSET * shift;
+               val = GEM_RX_SRC_SEL_GTR | GEM_SGMII_MODE;
+               val <<= GEM_CLK_CTRL_OFFSET * shift;
+               ret =  pm_mmio_write(IOU_GEM_CLK_CTRL, mask, val);
+       }
+
+       return ret;
+}
+
+/**
+ * pm_ioctl_sd_dll_reset() -  Reset DLL logic
+ * @nid                Node ID of the device
+ * @type       Reset type
+ *
+ * This function resets DLL logic for the SD device.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_sd_dll_reset(enum pm_node_id nid,
+                                               unsigned int type)
+{
+       unsigned int mask, val;
+       int ret;
+
+       if (nid == NODE_SD_0) {
+               mask = ZYNQMP_SD0_DLL_RST_MASK;
+               val = ZYNQMP_SD0_DLL_RST;
+       } else if (nid == NODE_SD_1) {
+               mask = ZYNQMP_SD1_DLL_RST_MASK;
+               val = ZYNQMP_SD1_DLL_RST;
+       } else {
+               return PM_RET_ERROR_ARGS;
+       }
+
+       switch (type) {
+       case PM_DLL_RESET_ASSERT:
+       case PM_DLL_RESET_PULSE:
+               ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, val);
+               if (ret)
+                       return ret;
+
+               if (type == PM_DLL_RESET_ASSERT)
+                       break;
+               mdelay(1);
+       case PM_DLL_RESET_RELEASE:
+               ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, 0);
+               break;
+       default:
+               ret = PM_RET_ERROR_ARGS;
+       }
+
+       return ret;
+}
+
+/**
+ * pm_ioctl_sd_set_tapdelay() -  Set tap delay for the SD device
+ * @nid                Node ID of the device
+ * @type       Type of tap delay to set (input/output)
+ * @value      Value to set fot the tap delay
+ *
+ * This function sets input/output tap delay for the SD device.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid,
+                                                  enum tap_delay_type type,
+                                                  unsigned int value)
+{
+       unsigned int shift;
+       int ret;
+
+       if (nid == NODE_SD_0)
+               shift = 0;
+       else if (nid == NODE_SD_1)
+               shift = ZYNQMP_SD_TAP_OFFSET;
+       else
+               return PM_RET_ERROR_ARGS;
+
+       ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT);
+       if (ret)
+               return ret;
+
+       if (type == PM_TAPDELAY_INPUT) {
+               ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+                                   ZYNQMP_SD_ITAPCHGWIN_MASK << shift,
+                                   ZYNQMP_SD_ITAPCHGWIN << shift);
+               if (ret)
+                       goto reset_release;
+               ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+                                   ZYNQMP_SD_ITAPDLYENA_MASK << shift,
+                                   ZYNQMP_SD_ITAPDLYENA << shift);
+               if (ret)
+                       goto reset_release;
+               ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+                                   ZYNQMP_SD_ITAPDLYSEL_MASK << shift,
+                                   value << shift);
+               if (ret)
+                       goto reset_release;
+               ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+                                   ZYNQMP_SD_ITAPCHGWIN_MASK << shift, 0);
+       } else if (type == PM_TAPDELAY_OUTPUT) {
+               ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
+                                   ZYNQMP_SD_OTAPDLYENA_MASK << shift,
+                                   ZYNQMP_SD_OTAPDLYENA << shift);
+               if (ret)
+                       goto reset_release;
+               ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
+                                   ZYNQMP_SD_OTAPDLYSEL_MASK << shift,
+                                   value << shift);
+       } else {
+               ret = PM_RET_ERROR_ARGS;
+       }
+
+reset_release:
+       ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
 /**
  * pm_api_ioctl() -  PM IOCTL API for device control and configs
  * @node_id    Node ID of the device
@@ -173,6 +362,18 @@ enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
        case IOCTL_TCM_COMB_CONFIG:
                ret = pm_ioctl_config_tcm_comb(arg1);
                break;
+       case IOCTL_SET_TAPDELAY_BYPASS:
+               ret = pm_ioctl_set_tapdelay_bypass(arg1, arg2);
+               break;
+       case IOCTL_SET_SGMII_MODE:
+               ret = pm_ioctl_set_sgmii_mode(nid, arg1);
+               break;
+       case IOCTL_SD_DLL_RESET:
+               ret = pm_ioctl_sd_dll_reset(nid, arg1);
+               break;
+       case IOCTL_SET_SD_TAPDELAY:
+               ret = pm_ioctl_sd_set_tapdelay(nid, arg1, arg2);
+               break;
        default:
                ret = PM_RET_ERROR_NOTSUPPORTED;
        }
index 9dae69fed70933ae42bafd5497e94e76c7a54543..a7f14a477418e8cdd98d355cd3555f588051b70b 100644 (file)
@@ -18,6 +18,10 @@ enum pm_ioctl_id {
        IOCTL_SET_RPU_OPER_MODE,
        IOCTL_RPU_BOOT_ADDR_CONFIG,
        IOCTL_TCM_COMB_CONFIG,
+       IOCTL_SET_TAPDELAY_BYPASS,
+       IOCTL_SET_SGMII_MODE,
+       IOCTL_SD_DLL_RESET,
+       IOCTL_SET_SD_TAPDELAY,
 };
 
 enum rpu_oper_mode {
@@ -35,6 +39,34 @@ enum rpu_tcm_comb {
        PM_RPU_TCM_COMB,
 };
 
+enum tap_delay_signal_type {
+       PM_TAPDELAY_NAND_DQS_IN,
+       PM_TAPDELAY_NAND_DQS_OUT,
+       PM_TAPDELAY_QSPI,
+       PM_TAPDELAY_MAX,
+};
+
+enum tap_delay_bypass_ctrl {
+       PM_TAPDELAY_BYPASS_DISABLE,
+       PM_TAPDELAY_BYPASS_ENABLE,
+};
+
+enum sgmii_mode {
+       PM_SGMII_DISABLE,
+       PM_SGMII_ENABLE,
+};
+
+enum tap_delay_type {
+       PM_TAPDELAY_INPUT,
+       PM_TAPDELAY_OUTPUT,
+};
+
+enum dll_reset_type {
+       PM_DLL_RESET_ASSERT,
+       PM_DLL_RESET_RELEASE,
+       PM_DLL_RESET_PULSE,
+};
+
 enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
                                unsigned int ioctl_id,
                                unsigned int arg1,
index 54036f99bbc6b01a39ea3c87868d83455d4a7b2a..f3180e901d441158f6b742222118a14f40879ce8 100644 (file)
 #define ZYNQMP_SLCLAMP_MASK                    0x10
 #define ZYNQMP_VINITHI_MASK                    0x04
 
+/* Tap delay bypass */
+#define IOU_TAPDLY_BYPASS                      0XFF180390
+#define TAP_DELAY_MASK                         0x7
+
+/* SGMII mode */
+#define IOU_GEM_CTRL                           0xFF180360
+#define IOU_GEM_CLK_CTRL                       0xFF180308
+#define SGMII_SD_MASK                          0x3
+#define SGMII_SD_OFFSET                                2
+#define SGMII_PCS_SD_0                         0x0
+#define SGMII_PCS_SD_1                         0x1
+#define SGMII_PCS_SD_PHY                       0x2
+#define GEM_SGMII_MASK                         0x4
+#define GEM_CLK_CTRL_MASK                      0xF
+#define GEM_CLK_CTRL_OFFSET                    5
+#define GEM_RX_SRC_SEL_GTR                     0x1
+#define GEM_SGMII_MODE                         0x4
+
+/* SD DLL reset */
+#define ZYNQMP_SD_DLL_CTRL                     0xFF180358
+#define ZYNQMP_SD0_DLL_RST_MASK                        0x00000004
+#define ZYNQMP_SD0_DLL_RST                     0x00000004
+#define ZYNQMP_SD1_DLL_RST_MASK                        0x00040000
+#define ZYNQMP_SD1_DLL_RST                     0x00040000
+
+/* SD tap delay */
+#define ZYNQMP_SD_DLL_CTRL                     0xFF180358
+#define ZYNQMP_SD_ITAP_DLY                     0xFF180314
+#define ZYNQMP_SD_OTAP_DLY                     0xFF180318
+#define ZYNQMP_SD_TAP_OFFSET                   16
+#define ZYNQMP_SD_ITAPCHGWIN_MASK              0x200
+#define ZYNQMP_SD_ITAPCHGWIN                   0x200
+#define ZYNQMP_SD_ITAPDLYENA_MASK              0x100
+#define ZYNQMP_SD_ITAPDLYENA                   0x100
+#define ZYNQMP_SD_ITAPDLYSEL_MASK              0xFF
+#define ZYNQMP_SD_OTAPDLYSEL_MASK              0x3F
+#define ZYNQMP_SD_OTAPDLYENA_MASK              0x40
+#define ZYNQMP_SD_OTAPDLYENA                   0x40
+
 #endif /* __ZYNQMP_DEF_H__ */